﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using PacketRush.Core;

namespace PacketRush.Services.Commanding
{
    public abstract class CommandService : INetService
    {
        public static Regex CommandArgsRegexPattern = new Regex(@"""(?<arg>[^""\\]*(?:\\.[^""\\]*)*)""|(?<arg>[^ ]+)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

        public event EventHandler<BadCommandEventArgs> BadCommand;
        protected virtual void OnBadCommand(string command, BadCommandReason reason)
        {
            if (BadCommand != null)
            {
                BadCommand(this, new BadCommandEventArgs() { Reason = reason, Command = command });
            }
        }

        protected Dictionary<string, Command> _Commands = new Dictionary<string, Command>(8);

        public abstract void DeliverPacket(Packet packet);

        public abstract Packet CollectPacket();

        public void AddCommand(Command command)
        {
            string commandName = command.CommandName.ToLower();
            if (!_Commands.ContainsKey(commandName))
            {
                _Commands.Add(commandName, command);
            }
        }

        public void RemoveCommand(string commandName)
        {
            if (String.IsNullOrEmpty(commandName)) return;

            commandName = commandName.ToLower();

            if (_Commands.ContainsKey(commandName))
            {
                _Commands.Remove(commandName);
            }
        }

        public Command FindCommand(string commandName)
        {
            if (String.IsNullOrEmpty(commandName)) return null;

            commandName = commandName.ToLower();
            Command command = null;
            if (_Commands.ContainsKey(commandName))
            {
                command = _Commands[commandName];
            }

            return command;
        }

        public bool ExecuteCommand(string command)
        {
            if (String.IsNullOrEmpty(command))
            {
                OnBadCommand(null, BadCommandReason.EmptyOrNull);
                return false;
            }

            MatchCollection matches = CommandArgsRegexPattern.Matches(command);

            if (matches.Count > 1)
            {
                string[] args = new string[matches.Count - 1];

                for (int i = 1; i < matches.Count; i++) args[i - 1] = matches[i].Groups["arg"].Value;

                if (ExecuteCommand(matches[0].Value, args)) return true;

            }
            else if (matches.Count == 1)
            {
                if (ExecuteCommand(command, null)) return true;
            }

            return false;
        }

        public bool ExecuteCommand(string commandName, string[] args)
        {
            if (String.IsNullOrEmpty(commandName))
            {
                OnBadCommand(null, BadCommandReason.EmptyOrNull);
                return false;
            }

            Command command = FindCommand(commandName);
            if (command != null)
            {
                command.ExecuteCommand(args);
                return true;
            }

            OnBadCommand(commandName, BadCommandReason.NotFound);

            return false;
        }
    }
}
